home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Games / cbzone / c_scores.c < prev    next >
C/C++ Source or Header  |  1995-05-03  |  9KB  |  338 lines

  1. #include "c_includes.h"
  2. /*
  3.  * cbzone_scores.c
  4.  *  -- Todd W Mummert, December 1990, CMU
  5.  *
  6.  * RCS Info
  7.  *  $Header: c_scores.c,v 1.1 93/02/25 13:39:04 iv Locked $
  8.  *
  9.  *  Derived from work I did on our local version of golddig.  Thanks
  10.  *  to Bennet Yee (CMU) for the flock() code.
  11.  */
  12.   
  13. /*
  14.  * Okay, let's try to clean this up.  The following things may
  15.  * happen:
  16.  *   score < 0:  then the user is just asking for scores.  the score
  17.  *               file should not be changed.
  18.  *   score >= 0: score is either valid, for practice, or played by an
  19.  *               old version.  In all cases, the file should change.
  20.  *
  21.  *   file status:
  22.  *     can be not there
  23.  *            available for reading
  24.  *            available for both reading and writing
  25.  *            not there but can be written
  26.  *
  27.  * we know the following:
  28.  *   whether the game was for practice only.
  29.  *   any scores in the score file WILL be in the correct order.
  30.  *
  31.  *  the format of the score file is as follows:
  32.  *    Version identification
  33.  *    number of games played, followed by number of valid games
  34.  *    scores, one per line w/uid and player's name
  35.  *
  36.  * how should we go about comparing users?
  37.  *  use getuid and cuserid...check both of them since we may be
  38.  *  saving scores over a distributed file system
  39.  *
  40.  * if the game was scoresonly, print to tty if opt->output allows;
  41.  *  else print to X screen.
  42.  */
  43.   
  44. extern int errno;
  45. int x, y, ydelta;
  46.  
  47.  
  48. void xprintf(s, output)                 /* print to the X screen */
  49.      char* s;
  50.      Bool output;
  51. {
  52.   printstring (x, y, s, strlen(s));
  53.   y += ydelta;
  54. }
  55.  
  56. void nprintf(s, output)                 /* print to the parent tty   */
  57.      char* s;
  58.      Bool output;
  59. {
  60.   if (output)
  61.     printf("%s\n", s);
  62. }
  63.  
  64. void printandwait(s, c)                 /* print a string and then */
  65.      char* s;                           /* wait for a character c  */
  66.      char c;                            /* to be pressed.  If c==0 */
  67. {                                       /* then any keypress will  */
  68.   y += ydelta;                          /* do.                     */
  69.   xprintf(s, True);
  70.   waitforkey(c);
  71. }
  72.  
  73. int scores(score)
  74.      int score;
  75. {
  76.   struct score_struct {
  77.     int score;
  78.     int uid;
  79.     char name[50];
  80.     struct score_struct *next;
  81.   } player, *current, *top_score, *prev_score;
  82.  
  83.   FILE *sfile;
  84.   char buf[100];
  85.   char version[100];
  86.   char *login, *getlogin();
  87.   int i;
  88.   Font fontid;
  89.   int numgame = 0;
  90.   int numscore = 0;
  91.   int numscoreable = 0;    
  92.   int player_scores = 0;
  93.   int tries = MAX_RETRIES;
  94.   Bool score_printed = False;
  95.   Bool scoresonly = False;
  96.   Bool wrong_version = False;
  97.   Bool file_readable = False;
  98.   Bool file_writeable = False;
  99.   Bool practice = opt->practice;
  100.   struct passwd* pw;
  101.   void (*p)();
  102.  
  103.   version[0] ='\0';
  104.   if (score < 0) {
  105.     practice = True;
  106.     scoresonly = True;
  107.     p = nprintf;
  108.   }
  109.   else {
  110.     p = xprintf;
  111.     gprsetclippingactive(False);
  112.     fontid = gprloadfontfile(GAMEOVERFONT);
  113.     gprsettextfont(fontid);
  114.     printstring (165, 300, "GAME OVER", 9);
  115.     fontid = gprloadfontfile(GENERALFONT);
  116.     gprsettextfont(fontid);
  117.     printstring (165, 320, "1986 JSR", 8);
  118.     flushwindow();
  119.     sleep(1);
  120.     clearentirescreen();
  121.   }
  122.  
  123.   x = 350;
  124.   y = 100;
  125.   ydelta = 15;
  126.  
  127.   sprintf(buf,"%s%s",TANKDIR,SCOREFILE);
  128.   sfile = fopen(buf,"r");    /* just check if it is there */
  129.  
  130.   if (sfile == NULL) {
  131.     p("Score file not readable.", opt->output);
  132.     if (scoresonly)
  133.       return 1;
  134.     else {
  135.       p("Will try and create new scorefile.", opt->output);
  136.     }
  137.   }
  138.   else
  139.     file_readable = True;
  140.  
  141.   if (!scoresonly) {
  142.     (void) signal(SIGINT, SIG_IGN); /* no leaving this routine */
  143.     (void) signal(SIGHUP, SIG_IGN); /* no how, no way */
  144.     file_writeable = True;
  145.     if (sfile != NULL)
  146.       fclose(sfile);
  147.     
  148.   retry:
  149.     if (file_readable)
  150.       sfile = fopen(buf,"r+");    /* okay, now open for update */
  151.     else
  152.       sfile = fopen(buf,"w");
  153.  
  154.     if (sfile == NULL) {
  155.       p("File not writeable, scores will not be saved.", opt->output);
  156.       file_writeable = False;
  157.     }
  158. #ifdef BSD
  159.     else {
  160.       if (flock(fileno(sfile),LOCK_EX) < 0) {
  161.         if (errno == EWOULDBLOCK && AFS) {
  162.           fclose(sfile);
  163.           sleep(AFS_SLEEP);
  164.           if (tries--)
  165.             goto retry;
  166.         }
  167.         p("File not lockable, scores will not be saved.", opt->output);
  168.         file_writeable = False;
  169.       }
  170.     }
  171. #endif /*BSD*/
  172.  
  173.     /* okay, it's possible we could have closed the file and never
  174.      * reopened it.  Also, we just may not have been able to lock
  175.      * it.  In either case, lets close it again and then open only
  176.      * for reading.
  177.      */
  178.     if (file_readable && !file_writeable) {
  179.       if (sfile != NULL)
  180.         fclose(sfile);
  181.       if ((sfile = fopen(buf, "r")) == NULL)
  182.         file_readable = False;
  183.     }
  184.   }
  185.  
  186.   if (!file_readable && !file_writeable) {
  187.     p("Scorefile not readable or writeable...Goodbye!", opt->output);
  188.     (void) signal(SIGINT, SIG_DFL); /* this would probably happen */
  189.     (void) signal(SIGHUP, SIG_DFL); /* on exit anyway             */
  190.     if (!scoresonly)
  191.       printandwait("Press any key to continue...", 0);
  192.     return 1;
  193.   }
  194.   
  195.   if (file_readable) {
  196.     if(fgets(version,200,sfile) && file_writeable) {
  197.       version[strlen(version)-1] = '\0'; /* strip the newline */
  198.       if (strcmp(version,VERSION)) {
  199.         wrong_version = True;
  200.         p("Incorrect version played for this scorefile.", opt->output);
  201.         p("Score not valid for inclusion.", opt->output);
  202.         sprintf(buf,"Your version is \"%s\", while",VERSION);
  203.         p(buf, opt->output);
  204.         sprintf(buf, "  the scorefile version is \"%s\"", version);
  205.         p(buf, opt->output);
  206.       }
  207.     }
  208.     
  209.     if (*version == '\0')
  210.       strcpy(version,VERSION);
  211.  
  212.     if(fgets(buf,200,sfile))
  213.       sscanf(buf,"%d %d",&numgame,&numscoreable);
  214.     top_score = (struct score_struct*) malloc(sizeof(struct score_struct));
  215.     current = top_score;
  216.     
  217.     while(fgets(buf,200,sfile) && numscore < NUMHIGH) 
  218.       if (sscanf(buf,"%d %d %[^\n]",¤t->score,
  219.                  ¤t->uid,current->name) != 3) {
  220.         p("Invalid line in score file...Skipping.", opt->output);
  221.       }
  222.       else {
  223.         current->next = (struct score_struct*)
  224.           malloc(sizeof(struct score_struct));
  225.         prev_score = current;
  226.         current = current->next;
  227.         numscore ++;
  228.       }
  229.   }
  230.   
  231.   if (numscore)
  232.     prev_score->next = NULL;
  233.   else
  234.     top_score = NULL;
  235.  
  236.   if (numgame < numscoreable)
  237.     numgame = numscoreable;
  238.  
  239.   if (!scoresonly) {
  240.     /* try to get it from the passwd file first, just in case this
  241.      * person su'd from another acct.
  242.      */
  243.     player.uid = getuid();
  244.     player.score = score;
  245.     pw = getpwuid(player.uid);
  246.     if (pw == NULL)
  247.       if ((login = getlogin()) != NULL)
  248.         strcpy(player.name, login);
  249.       else {
  250.         p("Can't find out who you are....bye.", opt->output);
  251.         fclose(sfile);
  252.         (void) signal(SIGINT, SIG_DFL);
  253.         (void) signal(SIGHUP, SIG_DFL);
  254.         if (!scoresonly) 
  255.           printandwait("Press any key to continue...", 0);
  256.         return 1;
  257.       }
  258.     else
  259.       strcpy(player.name, pw->pw_name);
  260.  
  261.     if (numscore < NUMHIGH || player.score > prev_score->score) {
  262.       score_printed = True;
  263.       numscore++;
  264.     
  265.       for (current = top_score;
  266.            current != NULL && player.score <= current->score;
  267.            prev_score = current, current = current->next);
  268.       
  269.       player.next = current;
  270.       
  271.       if (current == top_score)
  272.         top_score = &player;
  273.       else
  274.         prev_score->next = &player;
  275.     }
  276.  
  277.     numgame++;
  278.     if (!practice && !wrong_version)
  279.       numscoreable++;
  280.   }
  281.   
  282.   sprintf(buf, "High scores after %d games, %d scoreable:",
  283.           numgame, numscoreable);
  284.   p(buf, opt->output);
  285.   current = top_score;
  286.   while (current != NULL) {
  287.     if (current == &player)
  288.       *buf = '>';
  289.     else
  290.       *buf = ' ';
  291.     sprintf(buf+1, "%-20s %8d", current->name, current->score);
  292.     p(buf, opt->output);
  293.     
  294.     if (((wrong_version || practice) && current==&player) ||
  295.         (current->uid==player.uid && !strcmp(player.name, current->name) &&
  296.          ++player_scores>INDIVIDUAL_SCORES)) {
  297.       numscore--;
  298.       if (current == top_score) 
  299.         top_score = current->next;
  300.       else 
  301.         prev_score->next = current->next;
  302.     }
  303.     else
  304.       prev_score = current;
  305.     current = current->next;
  306.   }
  307.  
  308.   if (!scoresonly && !score_printed) {
  309.     p("...", opt->output);
  310.     sprintf(buf, ">%-20s %8d", player.name,player.score);
  311.     p(buf, opt->output);
  312.   }
  313.  
  314.   if (file_writeable) {
  315.     rewind(sfile);
  316.     fprintf(sfile,"%s\n",version);
  317.     fprintf(sfile,"%d %d\n",numgame,numscoreable);
  318.     for(current = top_score, i = 0;
  319.         current != NULL && i < NUMHIGH;
  320.         current = current->next, i++)
  321.       fprintf(sfile,"%d %d %s\n",current->score,current->uid,current->name);
  322.     if (practice) {
  323.       y += ydelta;
  324.       p("Your game was for practice only...", opt->output);
  325.       p("For a valid score use:  cbzone [-q] [-d 0-5]", opt->output);
  326.     }
  327.   }
  328.   
  329.   fclose(sfile);
  330.   (void) signal(SIGINT, SIG_DFL);
  331.   (void) signal(SIGHUP, SIG_DFL);
  332.  
  333.   if (!scoresonly)
  334.     printandwait("Press any key when ready...", 0);
  335.   
  336.   return 0;
  337. }
  338.